<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>数字输入框组件</title>
  <link href="https://cdn.bootcss.com/normalize/8.0.0/normalize.css" rel="stylesheet">
  <script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
  <style lang="">
    #app {
      width: 960px;
      margin: 20px auto;
      border: 1px solid #ccc;
    }
  </style>
</head>
<body>
  <div id="app">
    <p>数字输入框只能输入数字，而且有两个快捷按钮，可以直接减1或加1。</p>
    <input-number v-model="value" :max="10" :min="0">
      
    </input-number>
  </div>
  <script>
    function isValueNumber (value) {
      return (/(^-?[0-9]+\.{1}\d+$)|(^-?[1-9][0-9]*$)|(^-?0{1}$)/).test(value + '');
    }
    Vue.component('input-number', {
      template: '\
        <div class="input-number"> \
          <input \
            type="text" \
            :value="currentValue" \
            @change="handleChange"> \
          <button \
            @click="handleDown" \
            :disabled="currentValue <= min">-</button> \
          <button \
            @click="handleUp" \
            :disabled="currentValue >= max">+</button> \
        </div>',
      props: {
        max: {
          type: Number,
          default: Infinity
        },
        min: {
          type: Number,
          default: -Infinity
        },
        value: {
          type: Number,
          default: 0
        }
      },
      data: function() {
        return {
          currentValue: this.value
        }
      },
      watch: {
        currentValue: function (val) {
          this.$emit('input', val);
          this.$emit('on-change', val);
        },
        value: function (val) {
          this.updateValue(val);
        }
      },
      methods: {
        updateValue: function (val) {
          if (val > this.max) val = this.max;
          if (val < this.min) val = this.min;
          this.currentValue = val;
        },
        handleDown: function () {
          if (this.currentValue <= this.min) return;
          this.currentValue -= 1;
        },
        handleUp: function () {
          if (this.currentValue >= this.max) return;
          this.currentValue += 1;
        },
        handleChange: function (event) {
          var val = event.target.value.trim();
          var max = this.max;
          var min = this.min;
          if (isValueNumber(val)) {
            val = Number(val);
            this.currentValue = val;

            if (val > max) {
              this.currentValue = max;
            } else if (val < min) {
              this.currentValue = min;
            }
          } else {
            event.target.value = this.currentValue;
          }
        },
        mounted: function () {
          this.updateValue(this.value);
        }
      }

    });

    var app = new Vue({ 
        el: '#app',
        data: {
          value: 5
        }

    });
  </script>
</body>
</html>